#ifndef __M_DB_H__
#define __M_DB_H__
#include <mutex>
#include <assert.h>
#include "util.hpp"

class user_table{
private:
    MYSQL *_mysql;
    std::mutex _mutex;

public:
    user_table(const std::string &host,
                const std::string &username,
                const std::string &password,
                const std::string &dbname,
                uint16_t port = 3306){
        _mysql = mysql_util::mysql_creat(host,username,password,dbname,port);
        assert(_mysql != nullptr);
    }
    ~user_table(){
        mysql_util::mysql_destroy(_mysql);
        _mysql = nullptr;
    }

public:
    //添加新用户(输入username,password)
    bool insert(Json::Value &user)
    {
        //组织sql语句
        #define INSERT_USER "insert user values(null,'%s',password('%s'),1000,0,0);"//编号 昵称 密码 天梯初始分 总场次 胜场次
        char sql[4096] = {0}; 
        if(user["username"].isNull() || user["password"].isNull())
        {
            DLOG("INPUT USERNAME OR PASSWORD");
            return false;
        }  
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("insert user info failed!\n");
                return false;
            }
        }

        return true;
    }

    //用户登录(user中有usernam，password)
    bool login(Json::Value &user)
    {
        
#define LOGIN_USER "select id, score, total_count, win_count from user where username = '%s' and password = password('%s');"
        char sql[4096] = {0};
        if(user["username"].isNull() || user["password"].isNull())
        {
            DLOG("INPUT USERNAME OR PASSWORD");
            return false;
        }
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());

        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("user login failed!\n");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                DLOG("have no login user info!\n");
                return false;
            }
        }

        
        int resRow = mysql_num_rows(res);
        if(resRow != 1)//用户应该是唯一的
        {
            if(resRow == 0)
            {
                DLOG("wrong password");
                return false;
            }
            DLOG("the user info queried is not unique");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);

        return true;
    }

    //通过昵称获取用户
    bool select_by_name(const std::string &name,Json::Value &user)
    {
#define USER_BY_NAME "select id, score, total_count, win_count from user where username = '%s';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_NAME,name.c_str());

        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("get user info by name failed!\n");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                DLOG("have no the user info!\n");
                return false;
            }
        }

        int resRow = mysql_num_rows(res);
        if(resRow != 1)//用户应该是唯一的
        {
            if(resRow == 0)
            {
                DLOG("The user information is not");
                return false;
            }
            DLOG("the user info queried is not unique");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["username"] = name;
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);

        return true;
    }

    //通过id获取用户信息
    bool select_by_id(const uint64_t &id,Json::Value &user)
    {
        #define USER_BY_ID "select username, score, total_count, win_count from user where id = '%d';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_ID,id);

        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("get user info by id failed!\n");
                return false;
            }
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                DLOG("have no the user info!\n");
                return false;
            }
        }
        int resRow = mysql_num_rows(res);
        if(resRow != 1)//用户应该是唯一的
        {
            if(resRow == 0)
            {
                DLOG("The user information is not exist");
                return false;
            }
            DLOG("the user info queried is not unique");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[0];
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);

        return true;
    }

    //胜利后的操作
    bool win(int id)
    {
#define USER_WIN "update user set score = score + 30,total_count = total_count + 1,win_count = win_count + 1 where id = '%d';"
        char sql[4096] = {0};
        sprintf(sql,USER_WIN,id);
        
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("updata win user info failed!");
                return false;
            }
        }
        return true;
    }

    //失败后的操作
    bool lose(int id)
    {
#define USER_LOSE "update user set score = score - 30, total_count = total_count + 1 where id = '%d';"
        char sql[4096] = {0};
        sprintf(sql,USER_LOSE,id);
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(mysql_util::mysql_exec(_mysql,sql) == false)
            {
                DLOG("updata lose user info failed!");
                return false;
            }
        }
        return true;
    }
};

#endif